﻿using PetaPoco;
using PmSoft.Data.Abstractions;
using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;

namespace PmSoft.Data.PetaPoco;

/// <summary>
/// PetaPoco 实体映射器，用于自定义实体类与数据库表之间的映射规则。
/// </summary>
public class PetaPocoEntityMapper : IMapper
{
	private static readonly IDbNamesResolver _namesResolver = new SnakeNamesResolver();

	/// <summary>
	/// 获取或设置从数据库转换的逻辑。
	/// </summary>
	public Func<PropertyInfo, Type, Func<object, object>> FromDbConverter { get; set; }

	/// <summary>
	/// 获取或设置向数据库转换的逻辑。
	/// </summary>
	public Func<PropertyInfo, Func<object, object>> ToDbConverter { get; set; }

	/// <summary>
	/// 初始化 <see cref="PetaPocoEntityMapper"/> 类的新实例。
	/// </summary>
	public PetaPocoEntityMapper()
	{
		FromDbConverter = (propertyInfo, targetType) =>
		{
			if (propertyInfo != null)
			{
				var valueConverter = Attribute.GetCustomAttributes(propertyInfo, typeof(ValueConverterAttribute))
					.FirstOrDefault() as ValueConverterAttribute;
				if (valueConverter != null)
					return valueConverter.ConvertFromDb;
			}

			return null;
		};

		ToDbConverter = (propertyInfo) =>
		{
			if (propertyInfo != null)
			{
				var valueConverter = Attribute.GetCustomAttributes(propertyInfo, typeof(ValueConverterAttribute))
					.FirstOrDefault() as ValueConverterAttribute;
				if (valueConverter != null)
					return valueConverter.ConvertToDb;
			}

			return null;
		};
	}

	/// <summary>
	/// 获取列信息。
	/// </summary>
	/// <param name="pocoProperty">实体属性信息。</param>
	/// <returns>列信息。</returns>
	public ColumnInfo GetColumnInfo(PropertyInfo pocoProperty)
	{
		// 检查是否标记了NotMapped特性
		var notMappedAttribute = pocoProperty.GetCustomAttribute<NotMappedAttribute>();
		if (notMappedAttribute != null)
		{
			return null;
		}

		var columnInfo = new ColumnInfo();
		var columnAttribute = pocoProperty.GetCustomAttribute<System.ComponentModel.DataAnnotations.Schema.ColumnAttribute>();
		columnInfo.ColumnName = columnAttribute?.Name ?? _namesResolver.ResolveName(pocoProperty.Name);
		return columnInfo;
	}

	/// <summary>
	/// 获取从数据库转换的转换器。
	/// </summary>
	/// <param name="targetProperty">目标属性信息。</param>
	/// <param name="sourceType">源类型。</param>
	/// <returns>转换器函数。</returns>
	public Func<object, object> GetFromDbConverter(PropertyInfo targetProperty, Type sourceType)
	{
		return FromDbConverter.Invoke(targetProperty, sourceType);
	}

	/// <summary>
	/// 获取表信息。
	/// </summary>
	/// <param name="pocoType">实体类型。</param>
	/// <returns>表信息。</returns>
	public TableInfo GetTableInfo(Type pocoType)
	{
		var tableInfo = new TableInfo();
		var tableAttribute = pocoType.GetCustomAttribute<TableAttribute>();
		tableInfo.TableName = tableAttribute?.Name ?? _namesResolver.ResolveName(pocoType.Name);

		// 查找主键属性
		foreach (var property in pocoType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
		{
			var primaryKeyAttribute = property.GetCustomAttribute<Abstractions.Attributes.PrimaryKeyAttribute>();
			if (primaryKeyAttribute != null)
			{
				tableInfo.PrimaryKey = primaryKeyAttribute.Name ?? _namesResolver.ResolveName(property.Name);
				tableInfo.AutoIncrement = primaryKeyAttribute.IsIdentity;
				break;
			}
		}

		return tableInfo;
	}

	/// <summary>
	/// 获取向数据库转换的转换器。
	/// </summary>
	/// <param name="sourceProperty">源属性信息。</param>
	/// <returns>转换器函数。</returns>
	public Func<object, object> GetToDbConverter(PropertyInfo sourceProperty)
	{
		return ToDbConverter.Invoke(sourceProperty);
	}
}